<!doctype html>
<html lang="en">
    <head>
        <title>Emointor</title>
        <meta charset="utf-8">
         
         <link type="text/css" rel="stylesheet" href="stylesheets/materialize.css"  media="screen,projection"/> 
          
        <style>
            
            body {
                background-color:#ff5252;
                margin: 0px auto;                
            }

            #overlay {
                position: absolute;
                top: 0px;
                left: 0px;
                -o-transform : scaleX(-1);
                -webkit-transform : scaleX(-1);
                transform : scaleX(-1);
                -ms-filter : fliph; /*IE*/
                filter : fliph; /*IE*/
                width : 600px;
                height : 450px;
            }

            #videoel {
                -o-transform : scaleX(-1);
                -webkit-transform : scaleX(-1);
                transform : scaleX(-1);
                -ms-filter : fliph; /*IE*/
                filter : fliph; /*IE*/
                -o-border-radius:30px;
                -webkit-border-radius:30px;
                border-radius:30px;
                width : 600px;
                height : 450px;
            }
            
            #container {
                position : relative;
                width : 600px;
                /*margin : 0px auto;*/
            }
            
            #content {              
                margin-left : auto;
                margin-right : auto;
                max-width: 600px;
            }
            
            #sketch, #filter {
                display: none;
            }
            
            
            .btn {
                font-size: 16px;
            }

            #controls {   
                text-align: center;
            }

            #emotion_container {
                width: 600px;
            }

            #emotion_icons {
                height: 50px;
                /*padding-left: 30px;*/
            }

            .emotion_icon {
                width : 40px;
                height : 40px;
                margin-top: 5px;
                /*margin-left : 13px;*/
                /*margin-left : 35px;*/
            }
            #icon1{
                margin-left:-5px; 
            }
            #icon2{
                margin-left:140px;
            }
            #icon3{
                margin-left:135px;
            }

            #emotion_chart, #emotion_icons {
                margin: 0 auto;
                width : 400px;
            }

            #icon1, #icon2, #icon3 {
                visibility :hidden;
            }

            /* d3 */
            .bar {
                fill : steelblue;
                fill-opacity : .9;
            }
.col.happy {
  /*border: 1px solid #eee;*/
  margin: 7px 0;
  text-align: center;
  line-height: 5px;
  font-size: 15px;
  background-color: red;
  color: white;
  padding: 0;
}
.col.unhappy {
  /*border: 1px solid #eee;*/
  margin: 7px 0;
  text-align: center;
  line-height: 5px;
  font-size: 15px;
  background-color: blue;
  color: white;
  padding: 0;
}
.col.surprise {
  /*border: 1px solid #eee;*/
  margin: 7px 0;
  text-align: center;
  line-height: 5px;
  font-size: 15px;
  background-color: green;
  color: white;
  padding: 0;
}            
        </style>
    </head>
    <body >
        <script src="javascripts/utils.js"></script>
        <script src="javascripts/emonitor.min.js"></script>
        <script src="javascripts/model_pca_20_svm_emotionDetection.js"></script>
        <script src="javascripts/Stats.js"></script>
        <script src="javascripts/d3.min.js"></script>
        <script src="javascripts/emotion_classifier.js"></script>
        <script src="javascripts/emotionmodel.js"></script>
        <script type="text/javascript" src="javascripts/smoothie.js"></script>
        <script src="/socket.io/socket.io.js"></script>
        <script type="text/javascript" src="javascripts/jquery.min.js"></script>
		<script src="javascripts/model_spca_20_svm.js"></script>
		<script src="javascripts/dat.gui.min.js"></script>

        <nav>
            <div class="nav-wrapper">
              <a href="#" class="brand-logo center"><img src="images/logo_small.png"><span style="position:relative; bottom:8px">Emonitor</span></a>
              <ul id="nav-mobile" class="hide-on-med-and-down">
                <li class="right"><a class="modal-trigger" href="#modal1"><i class="mdi-action-account-child"></i></a></li>
                <li class="left"><a class="modal-trigger" href="#modal2"><i class="mdi-action-assignment"></i></a></li>  
                <li class="left"><a class="modal-trigger" href="#modal3"><i class="mdi-action-settings-applications"></i></a></li>                
              </ul>
            </div>
        </nav>
        

        <div id="content">
            <div id="container">
                <video id="videoel" width="400" height="300" preload="auto" loop class=" z-depth-1" >               
                </video>
                <canvas id="overlay" width="400" height="300"></canvas>
                <canvas id="sketch" width="400" height="300"></canvas>
                <div id="controls">
                    <a id="startbutton" class="waves-effect waves-light btn" onclick="startVideo()">Start</a>
                </div>
            </div>  
            
            <div id="emotion_container">
                <div id="emotion_icons">
                    <img class="emotion_icon" id="icon1" src="media/icon_sad.png">
                    <img class="emotion_icon" id="icon2" src="media/icon_happy.png">
                    <img class="emotion_icon" id="icon3" src="media/icon_surprised.png">
                </div>
                <div id='emotion_chart'></div>
                <div class="row">
                    <div class="col s4 unhappy">Unhappy</div>
                    <div class="col s4 happy">Happy</div>
                    <div class="col s4 surprise">Surprise</div>
                </div> 
                <canvas id="emonitor" width="600" height="100"></canvas>                               
            </div>
        </div>

  <!-- Modal1 Structure -->
  <div id="modal1" class="modal">
    <div class="modal-content">
      <div class="col s12 m8 offset-m2 l6 offset-l3">
        <div class="card-panel grey lighten-5 z-depth-1">
          <div class="row valign-wrapper">
            <div class="col s4">
              <img src="images/xiong.jpg" alt="" class="circle responsive-img"> 
            </div>
            <div class="col s10">
              <span class="black-text">
                <span class="mdi-social-person red-text accent-2"> Name:  </span>Eric Xiong<br>
                <span class="mdi-social-school red-text accent-2"> School:  </span>Chinese Academy of Sciences<br>
                <span class="mdi-action-book red-text accent-2"> Role:  </span>Engineer, Data Science Graduate Student<br>
                <span class="mdi-action-extension red-text accent-2"> Skills&Hobbies:  </span>Data Visualization, Nodejs, Computer Vision, Raspberry Pi, Intel Edison, Arduino<br>
                <span class="mdi-communication-email red-text accent-2"> Email:  </span>xiongzhp@outlook.com<br>
              </span>
            </div>
          </div>

          <div class="row valign-wrapper">
            <div class="col s4">
              <img src="images/Tao.jpg" alt="" class="circle responsive-img"> <!-- notice the "circle" class -->
            </div>
            <div class="col s10">
              <span class="black-text">
                <span class="mdi-social-person red-text accent-2"> Name:  </span>Tony Zhong<br>
                <span class="mdi-social-school red-text accent-2"> School:  </span>Chinese Academy of Sciences<br>
                <span class="mdi-action-book red-text accent-2"> Role:  </span>Designer, Pharmaceutics Graduate Student<br>
                <span class="mdi-action-extension red-text accent-2"> Skills&Hobbies:  </span>Google Materia Design, SketchUp, 3D printing, Solidworks, AI, Final Cut<br>
                <span class="mdi-communication-email red-text accent-2"> Email:  </span>575313339@qq.com
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="modal-footer">
      <a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">close</a>
    </div>
  </div>
    <!-- Modal2 Structure -->
  <div id="modal2" class="modal modal-fixed-footer">
    <div class="modal-content">
      <h5>Instructions</h5>
      <p>1) Allow the request to use your webcam (if the request didnot pop up), close current tab, reload the page from a different tab.</p>
      <p>2) Click Start!</p>
      <p>3) Our program will capture your face and rate your emotions in real-time.</p>
      <h5>What we have Done</h5>
      <p>This is a javascript implementation of face tracking and emotion detection, we built it with nodejs, emit extreme emotions with socket.io and store realtime quantified emotion data into mongodb. </p>
      <p>In addition, we figure out the mean of each quantified emotion(unhappy, happy, surprise) and the counts of extreme emotions in every minute, hours, or time span you want using mapreduce. </p>
      <p>Above all, we defined a new concept, Emotion Index, which is caculated in combination of the mean of quantified emotions and the counts of extreme emotions.</p><br>
      <h5>To-Do</h5>      
      <p>We made it run smoothly on Intel Edison and Raspeberry Pi, and we will get use of GPIO to make the hardware interact with you whenever extreme emotions are detected.</p>
      <p>We also plan to make an easy access hardware, which is capable of collecting as much emotion data as possible. For one thing, with the hardware, we can easily collect emotion data from people with psychological problems every day in psychology research, so we can get better understanding of mental disorders, like autism, depression and anxiety. For another, we can apply it in shopping mall for realtime feedback of products from visitors.</p>
      <p>What's your ideas? Contact us xiongzhp@outlook.com.</p>
    </div>
    <div class="modal-footer">
      <a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
    </div>
  </div>
  <!-- Modal3 Structure -->
    <div id="modal3" class="modal modal-fixed-footer">
    <div class="modal-content">
      <h5>How it works</h5>
      <p>You can see a face shape model consisting of some feature points and the line connecting the points. Tune the components(PCA components) with the control bar on the right, you will see different shapes of the face model, which simulates the various faces we captured from camera. Then, we compare the face sharp models with our well trained emotion models, and score them. That's how we quantify emotions.</p>
      <div>
		<canvas id="compare" style="position:relative;left:-50px;" width="600" height="550"></canvas>
		<div id="tune" style="position:relative;float:right"></div>
	  </div>      
    </div>
    <div class="modal-footer">
      <a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
    </div>
  </div>
            <script>
                var vid = document.getElementById('videoel');
                var overlay = document.getElementById('overlay');
                var overlayCC = overlay.getContext('2d');
                
                /********** check and set up video/webcam **********/

                function enablestart() {
                    var startbutton = document.getElementById('startbutton');
                    startbutton.value = "start";
                    startbutton.disabled = null;
                }
                
                
                navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
                window.URL = window.URL || window.webkitURL || window.msURL || window.mozURL;

                // check for camerasupport
                if (navigator.getUserMedia) {
                    // set up stream
                    
                    var videoSelector = {video : true};
                    if (window.navigator.appVersion.match(/Chrome\/(.*?) /)) {
                        var chromeVersion = parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10);
                        if (chromeVersion < 20) {
                            videoSelector = "video";
                        }
                    };
                
                    navigator.getUserMedia(videoSelector, function( stream ) {
                        if (vid.mozCaptureStream) {
                            vid.mozSrcObject = stream;
                        } else {
                            vid.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
                        }
                        vid.play();
                    }, function() {
                        //insertAltVideo(vid);
                        alert("There was some problem trying to fetch video from your webcam. If you have a webcam, please make sure to accept when the browser asks for access to your webcam.");
                    });
                } else {
                    //insertAltVideo(vid);
                    alert("This demo depends on getUserMedia, which your browser does not seem to support. :(");
                }

                vid.addEventListener('canplay', enablestart, false);
                
                /*********** setup of emotion detection *************/

                var ctrack = new clm.tracker({useWebGL : true});
                ctrack.init(pModel);

                function startVideo() {
                    // start video
                    vid.play();
                    startbutton.style.display="none";
                    // start tracking
                    ctrack.start(vid);
                    // start loop to draw face
                    drawLoop();
                    //monitor 
                    var strokecolor= ["rgb(0, 0, 255)","rgb(255, 0, 0)","rgb(0, 255, 0)"];
                    var line0 = new TimeSeries();
                    var line1 = new TimeSeries();
                    var line2 = new TimeSeries();
                    //emit extreme
                    var socket = io.connect();                  
                    setInterval(function() {
                        line0.append(new Date().getTime(), lineplot0);
                        line1.append(new Date().getTime(), lineplot1);
                        line2.append(new Date().getTime(), lineplot2);
var data = {};
    data.timeline = new Date().getTime();  
    data.unhappy = lineplot0; 
    data.happy = lineplot1; 
    data.surprise = lineplot2;

var epost = $.ajax( {    
    url:'/emotion',// 跳转到 action    
    data:JSON.stringify(data),
    type:'post',    
    cache:false,    
    contentType: 'application/json',  
    // success: function(data) {
    //     console.log('success');
    //                     },
    //  error : function() {    
    //       // view("异常！");    
    //       alert("异常！");    
    //  }    
});  
                        // if (lineplot2 > 0.4) {
                        // socket.emit('surprise',{to:'all',from:'Eric',msg:'Wow!!!!!!'});
                        // }
                        // if (lineplot0 > 0.4) {
                        // socket.emit('surprise',{to:'all',from:'Eric',msg:'我操!'});
                        // }
                        // if (lineplot1 > 0.9) {
                        // socket.emit('surprise',{to:'all',from:'Eric',msg:'哈哈!'});
                        // }

                    }, 500);
                    var smoothie = new SmoothieChart({ grid: { strokeStyle: 'rgb(125, 0, 0)', fillStyle: 'rgb(60, 0, 0)', lineWidth: 1, millisPerLine: 250, verticalSections: 6 } });
                    smoothie.addTimeSeries(line0, { strokeStyle: strokecolor[0], lineWidth: 2 });
                    smoothie.streamTo(document.getElementById("emonitor"), 1000);
                    smoothie.addTimeSeries(line1, { strokeStyle: strokecolor[1], lineWidth: 2 });
                    smoothie.streamTo(document.getElementById("emonitor"), 1000);
                    smoothie.addTimeSeries(line2, { strokeStyle: strokecolor[2], lineWidth: 2 });
                    smoothie.streamTo(document.getElementById("emonitor"), 1000);
                }
                
                function drawLoop() {
                    requestAnimFrame(drawLoop);
                    overlayCC.clearRect(0, 0, 400, 300);
                    // var escore = "score :" + ctrack.getScore().toFixed(4);
                    if (ctrack.getCurrentPosition()) {
                        ctrack.draw(overlay);
                    }
                    var cp = ctrack.getCurrentParameters(); 
                    var er = ec.meanPredict(cp);
                    
                    if (er) {
                        lineplot0 = er[0].value;
                        lineplot1 = er[1].value;
                        lineplot2 = er[2].value;
                        updateData(er);

                        for (var i = 0;i < er.length;i++) {
                            if (er[i].value > 0.4) {
                                document.getElementById('icon'+(i+1)).style.visibility = 'visible';
                            } else {
                                document.getElementById('icon'+(i+1)).style.visibility = 'hidden';
                            }

                        }

                    }
                }
                
                /*** emonitor ***/
                // function emonitor(){

                // }

                var ec = new emotionClassifier();
                ec.init(emotionModel);
                var emotionData = ec.getBlank();    
                
                /************ d3 code for barchart *****************/

                var margin = {top : 20, right : 0, bottom : 10, left : 0},
                    width = 400 - margin.left - margin.right,
                    height = 100 - margin.top - margin.bottom;

                var barWidth = 30;

                var formatPercent = d3.format(".0%");
                
                var x = d3.scale.linear()
                    .domain([0, 3]).range([0, 550]);

                var y = d3.scale.linear()
                    .domain([0,1]).range([0, height]);

                var svg = d3.select("#emotion_chart").append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                
                svg.selectAll("rect").
                  data(emotionData).
                  enter().
                  append("svg:rect").
                  attr("x", function(datum, index) { return x(index); }).
                  attr("y", function(datum) { return height - y(datum.value); }).
                  attr("height", function(datum) { return y(datum.value); }).
                  attr("width", barWidth).
                  attr("fill", "#2d578b");

                svg.selectAll("text.labels").
                  data(emotionData).
                  enter().
                  append("svg:text").
                  attr("x", function(datum, index) { return x(index) + barWidth; }).
                  attr("y", function(datum) { return height - y(datum.value); }).
                  attr("dx", -barWidth/2).
                  attr("dy", "1.2em").
                  attr("text-anchor", "middle").
                  text(function(datum) { return datum.value;}).
                  attr("fill", "white").
                  attr("class", "labels");
                

                function updateData(data) {
                    // update
                    var rects = svg.selectAll("rect")
                        .data(data)
                        .attr("y", function(datum) { return height - y(datum.value); })
                        .attr("height", function(datum) { return y(datum.value); });
                    var texts = svg.selectAll("text.labels")
                        .data(data)
                        .attr("y", function(datum) { return height - y(datum.value); })
                        .text(function(datum) { return datum.value.toFixed(1);});

                    // enter 
                    rects.enter().append("svg:rect");
                    texts.enter().append("svg:text");

                    // exit
                    rects.exit().remove();
                    texts.exit().remove();
                }

                /******** stats ********/

                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.top = '0px';
                document.getElementById('container').appendChild( stats.domElement );

                // update stats on every iteration
                document.addEventListener('clmtrackrIteration', function(event) {
                    stats.update();
                }, false);


            </script>
        </div>

<!-- modal3 js-->
		<script>
		  
		function rebuild() {
			// check how many parameters
			pnums = pModel.shapeModel.eigenValues.length;
			
			ph = new parameterHolder();
			gui.destroy();
			gui = new dat.GUI({ autoPlace: false });
			
			control = {};
			eig = 0;
			for (var i = 0;i < pnums;i++) {
				eig = Math.sqrt(pModel.shapeModel.eigenValues[i])*3
				control['c'+(i+1)] = gui.add(ph, 'component '+(i+1), -eig, eig);
			}
			
			for (var i = 0;i < pnums;i++) {
				control['c'+(i+1)].onChange(drawNew);
			}

			params = [];
			for (var i = 0;i < pnums;i++) {
				params.push(ph['component '+(i+1)]);
			}

			drawNew();
		}
		  
		var canvasInput = document.getElementById('compare');
		var cc = canvasInput.getContext('2d');
		cc.fillStyle = "rgb(200,0,0)";
		
		// check how many parameters
		var pnums = pModel.shapeModel.eigenValues.length;
		
		var parameterHolder = function() {
			for (var i = 0;i < pnums;i++) {
				this['component '+(i+1)] = 0;
			}
		};
			
		var ph = new parameterHolder();
		var gui = new dat.GUI({ autoPlace: false });
		var customContainer = document.getElementById('tune');
		customContainer.appendChild(gui.domElement);
	
		var control = {};
		var eig = 0;
		for (var i = 0;i < pnums;i++) {
			eig = Math.sqrt(pModel.shapeModel.eigenValues[i])*3
			control['c'+(i+1)] = gui.add(ph, 'component '+(i+1), -eig, eig);
		}
		
		var params;
		var drawNew = function(value) {
			cc.clearRect(0,0,600,600);
			params = [];
			for (var i = 0;i < pnums;i++) {
				params.push(ph['component '+(i+1)]);
			}
			draw(document.getElementById('compare'), similarityTransforms.concat(params));
		}
	
		for (var i = 0;i < pnums;i++) {
			control['c'+(i+1)].onChange(drawNew);
		}

		params = [];
		for (var i = 0;i < pnums;i++) {
			params.push(ph['component '+(i+1)]);
		}
	
		var similarityTransforms = [4,0,0,0];
		//var similarityTransforms = [1, 0, -250, -450];
		//var similarityTransforms = [1, 0, 200, 200];
		var paramslength = params.length;
		var num_points = pModel.shapeModel.numPtsPerSample;
			
		var x,y;
		
		var i, path;
		
		var drawPath = function(canvasContext, path, dp) {
			canvasContext.beginPath();
			var i, x, y;
			for (var p = 0;p < path.length;p++) {
				i = path[p]*2;
				x = pModel.shapeModel.meanShape[i/2][0];
				y = pModel.shapeModel.meanShape[i/2][1];
				for (var j = 0;j < pModel.shapeModel.numEvalues;j++) {
					x += pModel.shapeModel.eigenVectors[i][j]*dp[j+4];
					y += pModel.shapeModel.eigenVectors[i+1][j]*dp[j+4];
				}
				a = dp[0]*x - dp[1]*y + dp[2];
				b = dp[0]*y + dp[1]*x + dp[3];
				x += a;
				y += b;
				
				if (i == 0) {
					canvasContext.moveTo(x,y);
				} else {
					canvasContext.lineTo(x,y);
				}
			}
			canvasContext.moveTo(0,0);
			canvasContext.closePath();
			canvasContext.stroke();
		}
		
		function drawPoint(canvasContext, point, dp) {
			var i, x, y;
			i = point*2;
			x = pModel.shapeModel.meanShape[i/2][0];
			y = pModel.shapeModel.meanShape[i/2][1];
			for (var j = 0;j < pModel.shapeModel.numEvalues;j++) {
				x += pModel.shapeModel.eigenVectors[i][j]*dp[j+4];
				y += pModel.shapeModel.eigenVectors[i+1][j]*dp[j+4];
			}
			a = dp[0]*x - dp[1]*y + dp[2];
			b = dp[0]*y + dp[1]*x + dp[3];
			x += a;
			y += b;
			canvasContext.beginPath();
			canvasContext.arc(x, y, 2, 0, Math.PI*2, true);
			canvasContext.closePath();
			canvasContext.fill();
		}
	
		var draw = function(canvas, pv) {
			// if no previous points, just draw in the middle of canvas
			
			var params;
			if (pv === undefined) {
				params = currentParameters.slice(0);
			} else {
				params = pv.slice(0);
			}
			
			var cc = canvas.getContext('2d');
			cc.fillStyle = "rgb(0,0,0)";
			cc.strokeStyle = "rgb(0,0,0)";
			//cc.lineWidth = 1;
			cc.save();
			
			var paths = pModel.path.normal;
			for (var i = 0;i < paths.length;i++) {
				if (typeof(paths[i]) == 'number') {
					drawPoint(cc, paths[i], params);
				} else {
					drawPath(cc, paths[i], params);
				}
			}
			
			cc.restore()
	  	}
		draw(document.getElementById('compare'), similarityTransforms.concat(params))
		</script>    

    </body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="javascripts/materialize.min.js"></script>
<script>
 $(document).ready(function(){
    $('ul.tabs').tabs();
    $('.modal-trigger').leanModal();
  });
</script>

</html>
